package com.tyk.bookstore.front.product.service.impl;


import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tyk.bookstore.front.common.cache.anno.ICache;
import com.tyk.bookstore.front.common.cache.constant.CacheConstant;
import com.tyk.bookstore.front.common.core.model.vo.PageVo;
import com.tyk.bookstore.front.common.core.util.ObjUtil;
import com.tyk.bookstore.front.product.manager.ProductManager;
import com.tyk.bookstore.front.product.model.entity.AuthorDo;
import com.tyk.bookstore.front.product.model.entity.BookDo;
import com.tyk.bookstore.front.product.model.entity.BookStatisticDo;
import com.tyk.bookstore.front.product.model.enume.BookState;
import com.tyk.bookstore.front.product.model.query.CommonSearchQuery;
import com.tyk.bookstore.front.product.model.vo.BookPageVo;
import com.tyk.bookstore.front.product.repository.*;
import com.tyk.bookstore.front.product.service.SearchService;
import lombok.RequiredArgsConstructor;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;

import java.math.BigInteger;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author tyk
 * @description 商品搜素
 */
@Service
@RequiredArgsConstructor
public class SearchServiceImpl implements SearchService {
    private final BookRepository bookRepository;
    private final BookStatisticRepository bookStatisticRepository;
    private final AuthorRepository authorRepository;
    private final ProductManager productManager;


    @Override
    public BookPageVo commonSearch(CommonSearchQuery query) {
        // 查询
        SearchService searchService = (SearchService) AopContext.currentProxy();
        BookPageVo pv = searchService.searchFromDb(query);
        // 已登录则获取收藏、点赞信息
        if (StpUtil.isLogin()) {
            productManager.fillCollectedAndPraised(pv.getRecords());
        }
        return pv;
    }

    @Override
    @ICache(
            prefix = CacheConstant.SEARCH_COMMON_PREFIX,
            expireTime = CacheConstant.SEARCH_COMMON_EXPIRE_TIME,
            lockPrefix = CacheConstant.SEARCH_COMMON_LOCK_PREFIX
    )
    public BookPageVo searchFromDb(CommonSearchQuery query) {

        // 除排序外的条件
        LambdaQueryWrapper<BookDo> bw = buildCommonSearchQuery(query);
        bw.select(BookDo::getId);

        // 获取符合除排序条件之外的书籍的ID
        Set<Long> idSet = bookRepository
                .selectList(bw)
                .stream().map(BookDo::getId).collect(Collectors.toSet());

        // 特判（此操作必须，防止后续查询书籍信息时，in条件为空）
        if (idSet.isEmpty())
            return PageVo.instance(BookPageVo.class);

        // 调整分页参数
        int total = idSet.size();
        if (query.getLimit() > total) query.setLimit((long) total);
        if (query.getPage() * query.getLimit() > total)
            query.setPage((total + query.getLimit() - 1) / query.getLimit());

        // 将idList按照排序条件排序并分页=>得到所需页面统计数据
        LambdaQueryWrapper<BookStatisticDo> sw = Wrappers.lambdaQuery(BookStatisticDo.class);
        sw.in(BookStatisticDo::getBookId, idSet)
                .orderBy(true, !query.getDesc(), query.getSortOrder().toField())
                .orderByAsc(BookStatisticDo::getBookId)
                .last("limit " + (query.getPage() - 1) * query.getLimit() + "," + query.getLimit());
        List<BookStatisticDo> statisticList = bookStatisticRepository.selectList(sw);
        List<Long> idList = statisticList.stream().map(BookStatisticDo::getBookId).toList();

        // 查询书籍信息
        List<BookPageVo.Book> records = productManager.getBookPageVo$BookList(idList, statisticList);

        BookPageVo bpv = new BookPageVo();
        bpv.setTotal((long) total)
                .setCurrent(query.getPage())
                .setSize(query.getLimit())
                .setRecords(records);

        // 返回数据
        return bpv;
    }


    /**
     * 构建通用查询条件Wrapper
     *
     * @param query 查询参数
     * @return Wrapper
     */
    private LambdaQueryWrapper<BookDo> buildCommonSearchQuery(CommonSearchQuery query) {

        LambdaQueryWrapper<BookDo> w = Wrappers.lambdaQuery(BookDo.class);

        w.eq(BookDo::getState, BookState.ON);

        w.eq(ObjUtil.notBlank(query.getIsbn()), BookDo::getIsbn, query.getIsbn());

        String cid = query.getClassificationId();
        if (cid != null) {
            List<Long> cidList = productManager.findClazzLeafIdList(Long.valueOf(cid));
            if (ObjUtil.isEmpty(cidList)) {
                w.eq(BookDo::getId, BookDo.NOT_EXIST);
                return w;
            }
            w.in(BookDo::getClassificationId, cidList);
        }

        w.eq(query.getPublisherId() != null, BookDo::getPublisherId, query.getPublisherId());

        w.ge(query.getPublishTimeFrom() != null, BookDo::getPublishTime, query.getPublishTimeFrom());
        w.le(query.getPublishTimeTo() != null, BookDo::getPublishTime, query.getPublishTimeTo());

        w.ge(query.getPriceFrom() != null, BookDo::getPrice, query.getPriceFrom());
        w.le(query.getPriceTo() != null, BookDo::getPrice, query.getPriceTo());

        w.like(ObjUtil.notBlank(query.getKeyword()), BookDo::getTitle, query.getKeyword());

        w.like(ObjUtil.notBlank(query.getNameLike()), BookDo::getName, query.getNameLike());

        String authorName = query.getAuthorNameLike();
        if (ObjUtil.notBlank(authorName)) {
            List<Long> aidList = authorRepository.<BigInteger>selectSinList1Like(
                    AuthorDo::getId,
                    AuthorDo::getName, query.getAuthorNameLike(),
                    AuthorDo.class
            ).stream().map(it -> it.getV1().longValue()).toList();
            if (ObjUtil.isEmpty(aidList)) {
                w.eq(BookDo::getId, BookDo.NOT_EXIST);
                return w;
            }
            w.in(BookDo::getAuthorId, aidList);
        }

        return w;

    }


}
